/*
 * Initial class for smart peer review software.
 */
package conference;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * A class that models an academic conference for the 
 * manuscript review process.
 * @author Dan Garrison
 * @version Fall 2011
 */
public class Conference {
	String myTitle;
	Date myManuscriptDeadline;
	Date myReviewDeadline;
	Date myConferenceDeadline;
	List<Manuscript> myManuscriptList;
	List<ProgramChair> myProgramChairList;
	/**
	 * Construct an instance of the Conference Class.
	 * PROGRAM CHAIR LIST IS EMPTY AT CONSTRUCTION.
	 * <pre>
	 * -precondition: Arguments != null;
	 * </pre>
	 * @param theTitle the title of the conference.
	 * @param theManuscriptDeadline deadline for 
	 * manuscripts.
	 * @param theReviewDeadline deadline for reviews
	 * @param theConferenceDeadline conference date
	 * @param theManuscripts collection of manuscripts
	 */
	public Conference(String theTitle, 
					  Date theManuscriptDeadline,
					  Date theReviewDeadline,
					  Date theConferenceDeadline,
					  List<Manuscript> theManuscripts) {
		System.err.println("CAUTION: YOU ARE CREATING A" +
				"CONFERENCE THAT HAS NO PROGRAM CHAIR " +
				"USE OVERLOADED CONFERENCE THAT TAKES " +
				"A LIST OF PROGRAM CHAIR AS AURGUMENT.");
		myTitle = theTitle;
		myManuscriptDeadline = theManuscriptDeadline;
		myReviewDeadline = theReviewDeadline;
		myConferenceDeadline = theConferenceDeadline;
		myManuscriptList = theManuscripts;
		myProgramChairList = new ArrayList<ProgramChair>();
	}
	/**
	 * Construct an instance of the Conference Class.
	 * <pre>
	 * -precondition: Arguments != null;
	 * </pre>
	 * @param theTitle the title of the conference.
	 * @param theManuscriptDeadline deadline for 
	 * manuscripts.
	 * @param theReviewDeadline deadline for reviews
	 * @param theConferenceDeadline conference date
	 * @param theManuscripts collection of manuscripts
	 */
	public Conference(String theTitle, 
					  Date theManuscriptDeadline,
					  Date theReviewDeadline,
					  Date theConferenceDeadline,
					  List<Manuscript> theManuscripts,
					  List<ProgramChair> thePcList) {
		myTitle = theTitle;
		myManuscriptDeadline = theManuscriptDeadline;
		myReviewDeadline = theReviewDeadline;
		myConferenceDeadline = theConferenceDeadline;
		myManuscriptList = theManuscripts;
		myProgramChairList = thePcList;
	}
	/**
	 * Submits a manuscript to the conference.
	 * <pre>
	 * precondition: theManuscript != null
	 * </pre>
	 * <post>
	 * postcondition: if theManuscript.getSubmissionDate() is after myConferenceDeadline, Manuscript will not be added.
	 * <\post>
	 * @param theManuscript the manuscript submission
	 * @return true if successfully added to manuscript
	 * collection
	 */
	public boolean submitManuscript(Manuscript 
									theManuscript) {
		boolean result = true;
		if (0 < theManuscript.getSubmissionDate().compareTo(myConferenceDeadline)){
			result = false;
		}
		else {
			if (myManuscriptList == null)
				myManuscriptList = new ArrayList<Manuscript>();
			
			myManuscriptList.add(theManuscript);
		}
		return result;
	}
	/**
	 * <pre>
	 * -precondition: none
	 * -postcondition: none
	 * </pre>
	 * @author Allison Graham
	 * @param theAuthor object of type Author used to 
	 * search manuscript list.
	 * @return a collection of manuscripts 
	 * created by theAuthor
	 */
	public final Manuscript[] getManuscriptByAuthor(
			final Author theAuthor) {
		List<Manuscript> by_author = 
			new ArrayList<Manuscript>();
		Manuscript[] result;
		for (Manuscript m : myManuscriptList) {
			if (theAuthor.comparePerson(m.getAuthor())){
				by_author.add(m);
			}
		}
		result = new Manuscript[by_author.size()];
		return by_author.toArray(result);
	}
	/**
	 * Updates the status of a manuscript.
	 * <br>
	 * -precondition: the_manuscript != null.
	 * <br>
	 * my_manuscript_list cannot be empty or null.
	 * @param the_manuscript the manuscript to update.
	 * @param the_status the status of the update.
	 */
	public Manuscript updateManuscript(Manuscript 
			the_manuscript, Status the_status) {
		Manuscript updated = new Manuscript(the_manuscript,
				the_status);
		myManuscriptList.remove(the_manuscript);
		myManuscriptList.add(updated);
		return updated;
	}
	/**
	 * Gets a sub collection of manuscripts by Reviewer.
	 * <pre>
	 * -precondition : none.
	 * -postcondition : none.
	 * </pre>
	 * @author Allison Graham
	 * @param the_reviewer reviewer to search by
	 * @return a collection that is a subset of the
	 * manuscript list that this reviewer is associated
	 * with.
	 */
	public final Manuscript [] getManuscriptByReviewer(
			final Reviewer the_reviewer) {
		List<Manuscript> by_reviewer = 
			new ArrayList<Manuscript>();
		Manuscript[] result;
		for (Manuscript m : myManuscriptList) {
			for (Review r : m.getReviews()){
				if (the_reviewer.comparePerson(
						r.getReviewer())){
						by_reviewer.add(m);
				}
			}
		}
		result = new Manuscript[by_reviewer.size()];
		return by_reviewer.toArray(result);
	}
	/**
	 * Returns a collection of all manuscripts.
	 * @return a collection of all manuscripts submitted
	 * for this conference.
	 */
	public Manuscript[] getAllManuscripts() {
		return (Manuscript[]) 
		myManuscriptList.toArray(
				new Manuscript[myManuscriptList.size()]);
	}
	/**
	 * Title of the Conference
	 * @return my_title
	 */
	public String getTitle() {
		return myTitle;
	}
	
	/**
	 * Deadline for the conference, or the conference date.
	 * @return myConferenceDeadline
	 */
	public Date getConferenceDeadline() {
		return myConferenceDeadline;
	}
	
	/**
	 * Deadline for Manuscript submission.
	 * @return myManuscriptDeadline
	 */
	public Date getManuscriptDeadline() {
		return myManuscriptDeadline;
	}
	
	/**
	 * Deadline for Review submission.
	 * @return myReviewDeadline
	 */
	public Date getReviewDeadline() {
		return myReviewDeadline;
	}
	
	/**
	 * Submits a given review for a given manuscript.
	 * <pre>
	 * -precondition : the_manuscript is not null.
	 * -postcondition : my_manuscript_list.size() 
	 * is equal to \old my_manuscript>list.size().
	 * -postcondition : the_manuscript.getReviews().size() 
	 * should equal new_manuscript.getReviews().size() + 1.
	 * -postcondition : the_review should be in 
	 * new_manuscript.getReviews().
	 * </pre>
	 * @param the_manuscript the manuscript to receive 
	 * the review.
	 * @param the_review the review to add to the 
	 * manuscript
	 * @author Allison Graham
	 * @return true if the review is successfully 
	 * submitted.
	 */
	public boolean submitReview(Manuscript the_manuscript,
								Review the_review) {
		List<Review> newReviewList = 
			new ArrayList<Review>(the_manuscript.
					getReviews());
		newReviewList.add(the_review);
		Manuscript newManuscript = 
			new Manuscript(the_manuscript, newReviewList);
		myManuscriptList.remove(the_manuscript);
		myManuscriptList.add(newManuscript);
		return true;
	}
	
	/**
	 * Replaces an old review with a new review in the manuscript collection.
	 * @param theManuscript The manuscript to add a review to.
	 * @param theOldReview The review to be replaced.
	 * @param theNewReview The new review to add to the manuscripts review collection.
	 * @author Allison Graham
	 */
	public void submitNewReview(final Manuscript theManuscript, final Review theOldReview, final Review theNewReview) {
		List<Review> reviewList = 
			new ArrayList<Review>(theManuscript.
					getReviews());
		reviewList.remove(theOldReview);
		reviewList.add(theNewReview);
		Manuscript newManuscript = 
			new Manuscript(theManuscript, reviewList);
		myManuscriptList.remove(theManuscript);
		myManuscriptList.add(newManuscript);
	}
	
	/**
	 * @return a collection of all Users of this conference
	 */
	public User[] getUsers() {
		Set<User> users = new HashSet<User>();
		User[] result;
		for(ProgramChair pc : myProgramChairList) {
			System.err.println("pc = " + pc.getLastCommaFirst());
			users.add((User) pc);
		}
		for(Manuscript m : myManuscriptList) {
			users.add((User) m.getAuthor());
			for(Review r : m.getReviews()) {
				users.add((User) r.getReviewer());
			}
		}
		result = new User[users.size()];
		return users.toArray(result);
	}
	/**
	 * @param theUser an object of type User.
	 * @return a collection of User objects representing
	 * all of the roles theUser can take on.
	 */
	public User[] getRolesByUser(User theUser) {
		Set<User> roles = new HashSet<User>();
		User[] result;
		roles.add(new Author(
			theUser.getFirstName(),
			theUser.getLastName(),
			theUser.getEmail()
		));
		for (int i = 0; i < myProgramChairList.size(); i++){
			if (myProgramChairList.get(i).
					comparePerson(theUser)) {
				roles.add(new ProgramChair(
						theUser.getFirstName(),
						theUser.getLastName(),
						theUser.getEmail()
				));
			}
		}
		for (Manuscript m : myManuscriptList) {
			for (Review r : m.getReviews()) {
				if (r.getReviewer().
						comparePerson(theUser)) {
					roles.add(new Reviewer(
						theUser.getFirstName(),
						theUser.getLastName(),
						theUser.getEmail()
					));
				}
			}
		}
		result = new User[roles.size()];
		return roles.toArray(result);
	}
	public void sortByAuthor() {
		Collections.sort(myManuscriptList, 
				new AuthorComparator());
	}
	public void sortByTitle() {
		Collections.sort(myManuscriptList, 
				new TitleComparator());
	}
	public void sortByReviewsComplete() {
		Collections.sort(myManuscriptList, 
				new ReviewComparator());
	}
	public void sortByStatus() {
		Collections.sort(myManuscriptList, 
				new StatusComparator());
	}
	
	/**
	 * Removes a given Manuscript from the manuscript collection.
	 * @param theManuscript The Manuscript to be removed from the collection.
	 * @author Allison Graham
	 */
	public void deleteManuscript(final Manuscript theManuscript) {
		myManuscriptList.remove(theManuscript);
	}
	
	/**
	 * Add a new Program chair to this conference.
	 * <pre>
	 * -precondition: theUser != null
	 * -postcondition: myPcList.size() = old.size() + 1
	 * -postcondition: myPcList contains 
	 * 	(ProgramChair)theUser
	 * </pre>
	 * @param theUser
	 */
	public void addProgramChair(User theUser) {
		myProgramChairList.add(new ProgramChair(
				theUser.getFirstName(),
				theUser.getLastName(),
				theUser.getEmail()));
	}
	
	/**
	 * Return a list of all the Program Chairs for this conference.
	 * <pre>
	 * -precondition: myProgramChairList != null
	 * </pre>
	 * @return myProgramChairList
	 */
	public List<ProgramChair> getProgramChairs(){
		return myProgramChairList;
	}
}
